package com.ssm.basis.web.jackson.dictionary;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.introspect.AnnotatedClass;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import com.fasterxml.jackson.databind.ser.VirtualBeanPropertyWriter;
import com.fasterxml.jackson.databind.util.Annotations;
import com.ssm.basis.service.dictionary.DictEnum;
import lombok.NoArgsConstructor;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.ssm.basis.service.constant.SecurityConstant.SUPPRESS_WARNING_ALL;
import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
import static org.springframework.core.annotation.AnnotatedElementUtils.findMergedAnnotation;
import static org.springframework.core.annotation.AnnotatedElementUtils.hasAnnotation;
import static org.springframework.util.StringUtils.hasLength;

@NoArgsConstructor
class BeanVirtualPropertyWriter extends VirtualBeanPropertyWriter {
    static IDictionaryTranslate dictionaryTranslate;
    /**
     * 字典默认后缀
     */
    static final String DICT_LABEL_SUFFIX = "_text";
    static final Map<Class<?>, List<Field>> fieldCache = CollectionUtils.newHashMap(800);

    public BeanVirtualPropertyWriter(BeanPropertyDefinition propDef, Annotations annotations, JavaType type) {
        super(propDef, annotations, type);
    }

    @Override
    @SuppressWarnings(SUPPRESS_WARNING_ALL)
    protected Object value(Object bean, JsonGenerator gen, SerializerProvider prov) throws Exception {
        for (Field field : fieldCache.get(bean.getClass())) {
            Dict annotation = findMergedAnnotation(field, Dict.class);
            String value = String.valueOf(field.get(bean));
            String dictValue = getDictTranslate(annotation, value);
            if (hasLength(dictValue)) {
                String fieldName = field.getName() + DICT_LABEL_SUFFIX;
                fieldName = hasLength(annotation.fieldName()) ? annotation.fieldName() : fieldName;
                gen.writeStringField(fieldName, dictValue);
            }
        }
        return null;
    }

    @Override
    public VirtualBeanPropertyWriter withConfig(MapperConfig<?> config, AnnotatedClass declaringClass,
                                                BeanPropertyDefinition propDef, JavaType type) {
        Class<?> clazz = declaringClass.getRawType();
        List<Field> fields = fieldCache.get(clazz);
        if (ObjectUtils.isEmpty(fields)) {
            fields = Arrays.stream(clazz.getDeclaredFields())
                    .filter(x -> hasAnnotation(x, Dict.class))
                    .collect(Collectors.toList());
            fields.forEach(ReflectionUtils::makeAccessible);
            fieldCache.put(clazz, fields);
        }
        return new BeanVirtualPropertyWriter(propDef, declaringClass.getAnnotations(), type);
    }

    String getDictTranslate(Dict dict, String code) {
        String type = dict.type();
        Class<? extends DictEnum> dictEnum = dict.dictEnum();

        String name = null;
        if (hasLength(type) && nonNull(dictionaryTranslate)) { // 优先数据库字典表翻译
            name = dictionaryTranslate.getNameByTypeAndCode(type, code);
        }
        if (isNull(name) && !dictEnum.equals(DictEnum.class)) { // 枚举翻译
            name = Arrays.stream(dictEnum.getEnumConstants()).filter(
                x -> x.getValue().equalsIgnoreCase(code)
            ).map(DictEnum::getDesc).findFirst().orElse(null);
        }
        return name;
    }
}